package drds.plus.datasource.thread;

import com.alibaba.druid.pool.DruidDataSource;
import drds.plus.datasource.configuration.DatabaseStatus;
import drds.plus.datasource.configuration.DatasourceConfiguration;
import drds.plus.datasource.configuration.DatasourceConfigurationParser;
import drds.plus.datasource.configuration.DatasourceHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * 全局配置监听,全局配置发生变化， 需要重新FLUSH数据源
 */
@Slf4j
public class DataBaseChange {
    private DatasourceHandler datasourceHandler;

    public DataBaseChange(DatasourceHandler datasourceHandler) {
        this.datasourceHandler = datasourceHandler;
    }

    public void onDataRecieved(String dataId, String data) {
        if (null == data) {
            return;
        }
        datasourceHandler.lock.lock();
        try {
            // 如果是全局配置发生变化，可能是IP,PORT,DBNAME,DBTYPE,STATUS
            DatasourceConfiguration datasourceConfiguration = DatasourceConfigurationParser.parseDatasourceConfiguration(data);
            DatasourceConfiguration cloneDatasourceConfiguration = datasourceHandler.runTimeDatasourceConfiguration.clone();
            // 是用推送的配置，覆盖当前的配置
            cloneDatasourceConfiguration.setIp(datasourceConfiguration.getIp());
            cloneDatasourceConfiguration.setPort(datasourceConfiguration.getPort());
            cloneDatasourceConfiguration.setDatabaseName(datasourceConfiguration.getDatabaseName());
            cloneDatasourceConfiguration.setDataBaseStatusString(datasourceConfiguration.getDataBaseStatusString());
            // 如果推送过来的数据库状态是 RW/R->NA,直接销毁掉数据源，以下业务逻辑不做处理
            if (DatabaseStatus.NA_STATUS != datasourceHandler.runTimeDatasourceConfiguration.getDataBaseStatus() && DatabaseStatus.NA_STATUS == datasourceConfiguration.getDataBaseStatus()) {
                try {
                    datasourceHandler.druidDataSource.close();
                    log.info("[DRUID NA STATUS PUSH] destroy DataSource !");
                } catch (Exception e) {
                    log.error("[DRUID NA STATUS PUSH] destroy DataSource  Error!", e);
                }
            } else {
                // 转换tAtomDsConfDO
                DruidDataSource druidDataSource;
                try {
                    druidDataSource = DatasourceHandler.createDruidDataSource(datasourceHandler.datasourceId, cloneDatasourceConfiguration);
                } catch (Exception e1) {
                    log.error("[DRUID GlobaConfError] createDruidDataSource Error! dataId : " + dataId + " configuration : " + data);
                    return;
                }
                // 检查转换后结果是否正确
                if (!DatasourceHandler.checkDruidDataSource(druidDataSource)) {
                    log.error("[DRUID GlobaConfError] dataSource Prams Error! dataId : " + dataId + " configuration : " + data);
                    return;
                }
                // 如果推送的状态时 NA->RW/R 时需要重新创建数据源，无需再刷新
                if (datasourceHandler.runTimeDatasourceConfiguration.getDataBaseStatus() == DatabaseStatus.NA_STATUS && (cloneDatasourceConfiguration.getDataBaseStatus() == DatabaseStatus.RW_STATUS || cloneDatasourceConfiguration.getDataBaseStatus() == DatabaseStatus.R_STATUS || cloneDatasourceConfiguration.getDataBaseStatus() == DatabaseStatus.W_STATUS)) {
                    // 创建数据源
                    try {
                        druidDataSource.init();
                        DruidDataSource newDruidDataSource = datasourceHandler.druidDataSource;
                        datasourceHandler.druidDataSource = druidDataSource;
                        newDruidDataSource.close();
                        log.info("[druid na->rw/r status pusher] recreate datasource !");
                    } catch (Exception e) {
                        log.error("[druid na->rw/r status pusher] recreate datasource error!", e);
                    }
                } else {
                    boolean needReCreate = needReCreate(datasourceHandler.runTimeDatasourceConfiguration, cloneDatasourceConfiguration);
                    // 如果发生的配置变化是否需要重建数据源
                    // druid 没有flush方法，只能重建数据源 jiechen.qzm
                    if (needReCreate) {
                        try {
                            // 更新数据源
                            druidDataSource.init();
                            DruidDataSource oldDruidDataSource = datasourceHandler.druidDataSource;
                            datasourceHandler.druidDataSource = druidDataSource;
                            oldDruidDataSource.close();
                            log.info("[druid config change status] always recreate datasource !");
                        } catch (Exception e) {
                            log.error("[druid create globaconf error]  always recreate datasource error !", e);
                        }
                    } else {
                        log.info("[druid create globaconf error]  global configuration is same!nothing will be done! the global configuration is:" + data);
                    }
                }
            }
            // 处理数据库状态监听器
            datasourceHandler.handle(datasourceHandler.runTimeDatasourceConfiguration.getDataBaseStatus(), cloneDatasourceConfiguration.getDataBaseStatus());
            // 是用新的配置覆盖运行时的配置
            datasourceHandler.runTimeDatasourceConfiguration = cloneDatasourceConfiguration;
            datasourceHandler.clearDataSourceWrapper();
        } catch (RuntimeException e) {
            throw e;
        } finally {
            datasourceHandler.lock.unlock();
        }
    }

    private boolean needReCreate(DatasourceConfiguration runTimeDatasourceConfiguration, DatasourceConfiguration newDatasourceConfiguration) {

        if (!runTimeDatasourceConfiguration.getIp().equals(newDatasourceConfiguration.getIp())) {
            return true;
        }
        if (!runTimeDatasourceConfiguration.getPort().equals(newDatasourceConfiguration.getPort())) {
            return true;
        }
        return !runTimeDatasourceConfiguration.getDatabaseName().equals(newDatasourceConfiguration.getDatabaseName());
    }

}
